package com.xpec.cipher.h5handler;

import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Random;

import com.xpec.c4.game.utility.GameUtility;
import com.xpec.cipher.CipherConnectionConstant;
import com.xpec.cipher.CipherHandler;
import com.xpec.cipher.algorithm.RC4;
import com.xpec.cipher.handler.CipherConnectionPacketHandler;
import com.xpec.cipher.tals.PseudoRandom;
import com.xpec.cipher.tals.TalsConstance;
import com.xpec.cipher.tals.record.ChangeKeyRecord;
import com.xpec.net.xnetty.h5cihper.H5BaseCipherChannelHandler;

public class H5ServerHandShakeCreateKeyHandler implements CipherConnectionPacketHandler
{
	private Random random = new Random(System.currentTimeMillis());

	private static KeyPairGenerator keyPairGenerator;

	static
	{
		try
		{
			keyPairGenerator = KeyPairGenerator.getInstance("RSA");
			// key size 2048b
			keyPairGenerator.initialize(new java.security.spec.RSAKeyGenParameterSpec(
				TalsConstance.RSA_MODULUS_SIZE * 8, BigInteger.valueOf(65537)));
		}
		catch (NoSuchAlgorithmException e)
		{
			e.printStackTrace();
		}
		catch (InvalidAlgorithmParameterException e)
		{
			e.printStackTrace();
		}
	}

	private static KeyPair keyPair  = keyPairGenerator.generateKeyPair();;

	@Override
	public void receiveHandle(CipherHandler cipherHandler)
	{
		// 接收到的是Client发过来的HandShake包
		int contentType = cipherHandler.readUnsignedByteFromRealContent();
		if (contentType == TalsConstance.CONTENT_TYPE_HAND_SHAKE)
		{
			int handShakeType = cipherHandler.readUnsignedByteFromRealContent();
			if (handShakeType == TalsConstance.HAND_SHAKE_TYPE_CLIENT_HELLO)
			{
				byte[] clientRandomTmp = null;
				if (cipherHandler.getRealContentRemain() == TalsConstance.CLIENT_HELLO_SIZE) {
					clientRandomTmp = new byte[TalsConstance.CLIENT_HELLO_SIZE];
				} else {
					clientRandomTmp = new byte[TalsConstance.CLIENT_ROBOT_HELLO_SIZE];
				}

				// 读取client hello
				cipherHandler.readByteFromRealContent(clientRandomTmp);

				// 機器人會在最後多帶一個 byte 識別是否為機器人
				boolean clientIsRobot = false;
				if (clientRandomTmp.length == TalsConstance.CLIENT_ROBOT_HELLO_SIZE) {
					byte b = clientRandomTmp[TalsConstance.CLIENT_ROBOT_HELLO_SIZE - 1];
					if (b == TalsConstance.CLIENT_ROBOT_IDENTIFY_KEY) {
						clientIsRobot = true;
					}
				}

				// 標記是否為機器人
				cipherHandler.setParameter(CipherConnectionConstant.PARA_KEY_CLIENT_IS_ROBOT, clientIsRobot);

				// 將資料放回原本的大小的陣列中
				byte[] clientRandom = new byte[TalsConstance.CLIENT_HELLO_SIZE];
				clientRandom = Arrays.copyOf(clientRandomTmp, TalsConstance.CLIENT_HELLO_SIZE);

				// 记录一下client的随机数
				cipherHandler.setParameter(CipherConnectionConstant.PARA_KEY_CLIENT_RANDOM,
					clientRandom);

				// 随机生成并发送server hello
				byte[] serverRandom = new byte[TalsConstance.SERVER_HELLO_SIZE];
				random.nextBytes(serverRandom);

				// 记录一下server的随机数
				cipherHandler.setParameter(CipherConnectionConstant.PARA_KEY_SERVER_RANDOM, serverRandom);

				
				byte cipherAlgorithm = H5BaseCipherChannelHandler.randomCipherAlgorithm();
				// hmac算法
				byte hmacAlgorithm = H5BaseCipherChannelHandler.randomHmacAlgorithm();

				cipherHandler.setParameter(CipherConnectionConstant.PARA_KEY_CIPHER_ALGO, cipherAlgorithm);
			
				cipherHandler.setParameter(CipherConnectionConstant.PARA_KEY_HMAC_ALGO, hmacAlgorithm);

				/**
				 * 生成 秘密前体 (pre master secret)
				 * 通讯握手阶段，客户端随机生成的46 Bytes随机内容，通过RSA Public加密后发给服务器。
				 */
				Random random = new Random(System.currentTimeMillis());
				byte[] preMasterSecret = new byte[ TalsConstance.PRE_SECRET_RANDOM_BYTES_SIZE ];
				random.nextBytes(preMasterSecret);
				
				byte[] masterKey = PseudoRandom.generatePRG(preMasterSecret, clientRandom, serverRandom);
				byte[] macKey = Arrays.copyOfRange(masterKey, 0, 16);
				byte[] key = Arrays.copyOfRange(masterKey, 32, 48);

				// 保存masterkey
				cipherHandler.setParameter(CipherConnectionConstant.PARA_KEY_MASTER_KEY, masterKey);
				cipherHandler.setParameter(CipherConnectionConstant.PARA_KEY_MAC_KEY, macKey);
				cipherHandler.setParameter(CipherConnectionConstant.PARA_KEY_KEY, key);
				cipherHandler.setParameter(CipherConnectionConstant.PARA_KEY_ENCRYPT_KEY, key);

				
				Object algo = genCipherAlgo(cipherHandler, key, cipherAlgorithm);
				if (null != algo)
					cipherHandler.setParameter(
							CipherConnectionConstant.PARA_KEY_SERVER_CIPHER_OBJECT, 
							algo);
				
				byte[] returnBuffer = GameUtility.appendByteArrays(masterKey, key);
				
				ChangeKeyRecord cRecord = new ChangeKeyRecord(returnBuffer);
				cipherHandler.sendData(cRecord.resolve(), true);

				//System.out.println("handShake finish!");
			}
		}
	}

	@Override
	public void sendHandle(CipherHandler cipherHandler)
	{
		cipherHandler.passMessage(CipherHandler.PASS_MESSAGE_SEND);
	}
	
	/**
	 * 通过Cihper算法和key生成好以后用于Cipher过程的算法对象。
	 * @author Francois
	 * @param cipherHandler
	 * @param key
	 * @param cipherAlgorithm
	 */
	protected static Object genCipherAlgo(CipherHandler cipherHandler, byte[] key,
			int cipherAlgorithm)
	{
		switch (cipherAlgorithm) {
		case TalsConstance.DATA_ENCRYPT_ALGORITHM_ARC4:
			RC4 algo = new RC4(key);
			return algo;
		}
		return null;
	}

}
